home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / stlogin4.lzh / TALK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-03  |  8.7 KB  |  412 lines

  1. /* TALK: (c) Kees Lemmens; April 1993.
  2.  
  3.    Behaviour is copied from the (BSD) UNIX talk program, but the
  4.    code is completely by myself.
  5.  
  6.    Program for ATARI ST (running under MINT) to make it possible
  7.    to talk with any other person logged in.
  8.    Relies on the utmp structure as defined in the stlogin.lzh
  9.    package (also by me).
  10.    If you don't have this, then you can only use the "-l tty"
  11.    option. Talk then assumes that the username is root, unless 
  12.    the variable LOGNAME is set.
  13.    
  14.    It also needs a termcap file for screen handling on non-ST
  15.    terminals. If you don't have termcap, talk uses vt52 (ST).
  16.    
  17.    Any questions or suggestions about this program can be send to:
  18.    lemmens@dv.twi.tudelft.nl
  19. */
  20.  
  21. /* standard headers */
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>        /* getenv, malloc, free and exit */
  25. #include <string.h>
  26. #include <time.h>
  27.  
  28. #include <osbind.h>
  29.  
  30. /* UNIX headers */
  31.  
  32. #include <utmp.h>
  33. #include <pwd.h>
  34. #include <termcap.h>
  35. #include <signal.h>        /* especially for suspend routine */
  36. #include <sys\file.h>    /* access */
  37. #include <sgtty.h>        /* ioctl & tty structs */
  38.  
  39. /* special headers */
  40. #include "ux_misc.h"    /* mk_devnm + MINT functions */
  41.  
  42. #define MASTER     0
  43. #define SLAVE      1
  44. #define UpWindow   0
  45. #define DownWindow 1
  46. #define Keyboard   1
  47.  
  48. typedef struct { int line, col; } WindowPos;
  49.  
  50. static char *_tcpent,*_tcpbuf;
  51. static char *CL,*CM,*SO,*SE,*CE;
  52. static int LINES,COLS;
  53. static WindowPos Up   = {1, 0};
  54. static WindowPos Down = {0, 0};
  55.  
  56. struct ltchars ltold,ltnew;    /* disable suspend */
  57.  
  58. void ttraw(struct ltchars *ltold,struct ltchars *ltnew)
  59. {
  60.     if(ioctl(0, TIOCGLTC, (char *) ltold) < 0)
  61.         puts("Can't do ioctl");
  62.     ioctl(0, TIOCGLTC, (char *)ltnew);
  63.  
  64.     ltnew->t_suspc = ltnew->t_dsuspc = 0xFF;
  65.     ioctl(0, TIOCSLTC, (char *) ltnew);
  66. }
  67.  
  68. void ttcooked(struct ltchars *ltold)
  69. {
  70.     ioctl(0, TIOCSLTC, (char *) ltold);
  71. }
  72.  
  73. void InitTermcap(void)
  74. {    char *tmp;
  75.  
  76.     if((tmp=getenv("TERM")) != NULL)    /* use UNIX termcap */
  77.     {    _tcpent = (char *)malloc(2048); /* must be enough ! */
  78.         tgetent(_tcpent,tmp);
  79.         _tcpbuf = _tcpent +1024;
  80.  
  81.         CL = tgetstr("cl", &_tcpbuf);    CM = tgetstr("cm", &_tcpbuf);
  82.         SO = tgetstr("so", &_tcpbuf);    SE = tgetstr("se", &_tcpbuf);
  83.         CE = tgetstr("ce", &_tcpbuf);
  84.         LINES = tgetnum("li");            COLS  = tgetnum("co");
  85.     }
  86.     else                /* set acceptable defaults : VT52 code */
  87.     {    CL = "\33H\33J";    CM = "\33Y%+ %+ ";
  88.         SO = "\33p";        SE = "\33q";
  89.         CE = "\33K";
  90.         LINES = 24;        COLS = 80;
  91.     }
  92. }
  93.  
  94. int outc(int c)
  95. {    return putchar(c);
  96. }
  97.  
  98. void clrscr(void)
  99. {    tputs(CL,1,outc);
  100. }
  101.  
  102. void gotoxy(int x,int y)
  103. { tputs(tgoto(CM, x, y),1,outc);
  104. }
  105.  
  106. void EndTermcap(void)
  107. {    free(_tcpent);
  108. }
  109.  
  110. void usage(void)
  111. {    fputs("\nUsage: talk [-l <line>] | [<username>]",stderr);
  112.     exit(1);
  113. }
  114.  
  115. void MsgPrint(char *string,int mode)
  116. {    static int upline=0;
  117.  
  118.     upline++;
  119.     if(mode || upline >= LINES/2)
  120.         upline = 0;
  121.  
  122.     gotoxy(0,upline);
  123.  
  124.     tputs(CE,1,outc);
  125.     puts(string);
  126. }
  127.  
  128. void InitScreen(void)
  129. {    int x;
  130.  
  131.     clrscr();
  132.     gotoxy(0,LINES/2);
  133.     for(x=0;x<COLS;x++)
  134.         fputc('-',stdout);
  135. }
  136.  
  137. int name2tty(char *name,char *totty)
  138. {    extern int utmp_fd;
  139.     int fl=1;
  140.     struct utmp *w;
  141.     
  142.     setutent();
  143.     
  144.     while((w=getutent()) != NULL)
  145.     {    if(!strncmp(w->ut_name,name,sizeof(w->ut_name)) &&
  146.             w->ut_type == USER_PROCESS)
  147.         {    if((fl=Pkill(w->ut_pid,SIGNULL)) != 0) 
  148.             {    /* process does not exist */
  149.                 w->ut_type=DEAD_PROCESS;
  150.                 setutent();        /* rewind and */
  151.                 pututline(w);    /* correct UTMP entry */
  152.             }
  153.             else break;
  154.         }
  155.     }
  156.     endutent();
  157.     if(fl) return -1;
  158.  
  159.     strncpy(totty,w->ut_line,sizeof(w->ut_line));
  160.     return 0;
  161. }
  162.  
  163. char *MakeChanName(char *name)
  164. {    static char pipenam[40];
  165.     
  166.     strcpy(pipenam,"U:\\PIPE\\");
  167.     strncat(pipenam,name,8);
  168.     strcat(pipenam,".tlk");
  169.  
  170.     return pipenam;
  171. }
  172.  
  173. int MakeChan(char *name, int mode)
  174. {    char *channel;
  175.     int fp;
  176.     int mask = (mode == MASTER ? O_CREAT : 0);
  177.     
  178.     channel = MakeChanName(name);
  179.     if((fp=open(channel,O_RDWR|mask)) < 0)
  180.     {    puts("Can't open pipe !");
  181.         exit(1);
  182.     }
  183.     return fp;
  184. }
  185.  
  186. char *BuildttyName(int lfl,char *name)
  187. {    static char fulltty[100];
  188.     char totty[20];
  189.  
  190.     if(lfl)
  191.         strncpy(totty,name,19);
  192.     else
  193.     {     if(name2tty(name,totty) < 0)
  194.         {    puts("[Your party is not logged on]");
  195.             exit(0);
  196.         }
  197.     }
  198.     mk_devnm(fulltty,totty);
  199.     return fulltty;
  200. }
  201.  
  202. int WaitforConnect(int channel)
  203. {    char tmp=0;
  204.  
  205.     write(channel,&tmp,1L);
  206.  
  207.     if(Finstat(Keyboard))
  208.     {    read(1,&tmp,1);
  209.         if(tmp=='\003' || tmp=='\004')
  210.             return -1;
  211.     }
  212.     if(Finstat(channel) == 0)
  213.     {    sleep(1);
  214.         return 0;
  215.     }
  216.     else
  217.     {    while(Finstat(channel))
  218.             read(channel,&tmp,1);    /* flush channel */
  219.  
  220.         InitScreen();
  221.         MsgPrint(    "[Connection established; quit=Ctrl-D;"
  222.                     " clrscr=Ctrl-L]",1);
  223.         return 1;
  224.     }
  225. }
  226.  
  227. void SuspendTalk(void)
  228. {    long omask;
  229.     
  230.     if (getenv("SHLVL") != NULL) /* there is a running (C) shell */
  231.     {    omask= sigsetmask(0);
  232.         ttcooked(<old);
  233.         (void) kill(0, SIGTSTP);
  234.         (void) Psigsetmask(omask);
  235.         ttraw(<old,<new);
  236.         InitScreen();
  237.         MsgPrint("[Connection resumed]",1);
  238.     }
  239.     else
  240.         MsgPrint("[No shell active]",1);
  241.     gotoxy(Up.col,Up.line);    /* restore cursor */
  242. }
  243.  
  244. void WindowSet(char c,WindowPos *pos,int window)
  245. {    static int previouswindow;
  246.     int offset=0;
  247.     
  248.     if (window == DownWindow)
  249.         offset = LINES/2 + 1;
  250.  
  251.     if(pos->col >= COLS || c == '\015')
  252.     {    pos->col=0; pos->line++;
  253.     
  254.         if(pos->line >= LINES/2)
  255.             pos->line=0;
  256.     }
  257.  
  258.     /* set or restore cursor position */
  259.     if (window != previouswindow || pos->col == 0)
  260.         gotoxy(pos->col,pos->line + offset);
  261.  
  262.     if(pos->col == 0)    /* clear line */
  263.         tputs(CE,1,outc);
  264.  
  265.     if (c == '\015')    /* simulate newline (looks better) */
  266.         gotoxy(pos->col,pos->line + offset);
  267.     else
  268.         putchar(c);
  269.  
  270.     pos->col++;
  271.     previouswindow = window;
  272. }
  273.  
  274. void StartTalk(int channel)
  275. {    char toggle=0, TalkChar=0;
  276.     
  277. /*
  278.     1: Ctrl-C interrupt doesn't give a stop signal to the other
  279.        side, so it must be captured to avoid problems.
  280.  
  281.     2: The toggle is used to give every side an equal chance.
  282.        This makes it impossible that a constant stream from one
  283.        side prevents the other the possibility to log off !
  284. */
  285.     signal(SIGINT,SIG_IGN);
  286.  
  287.     while(TalkChar!='\004')
  288.     {    if(toggle)
  289.         {    if(Finstat(channel))        /* other side */
  290.             {
  291.                 read(channel,&TalkChar,1);
  292.                 WindowSet(TalkChar,&Down,DownWindow);
  293.             }    
  294.         }
  295.         else
  296.         {    if(Finstat(Keyboard))        /* own side */
  297.             {
  298.                 /* don't echo: unfortunately sgttyb doesn't work */
  299.                 TalkChar=Cnecin();
  300.                 WindowSet(TalkChar,&Up,UpWindow);
  301.  
  302.                 if(TalkChar == '\014')    /* Ctrl-L: clear screen */
  303.                 {    InitScreen();
  304.                     Up.line = Up.col = Down.col = Down.line = 0;
  305.                     continue;
  306.                 }
  307.                 /* Ctrl-Z : jump to shell */
  308.  
  309.                 if(TalkChar == '\032')
  310.                 {    SuspendTalk();
  311.                     continue;
  312.                 }
  313.                 write(channel,&TalkChar,1);
  314.             }
  315.         }
  316.         toggle ^= 1;
  317.     }
  318. }
  319.  
  320. int SendInvitation(char *totty,char *name,int channel,int repeat)
  321. {    int st,x,fp;
  322.     time_t sec;
  323.     char *ttyname,message[250];
  324.     char *format=
  325.         "\07\r\nMessage from TalkDaemon@Atari.Ste at %.8s "
  326.         "...\r\ntalkd: Connection requested by %s (%s)"
  327.         "   \r\ntalkd: Please respond with: talk %s\r\n";
  328.  
  329.     if((ttyname = getenv("TTYNAME")) == NULL)
  330.         ttyname = "console";
  331.  
  332.     signal(SIGTTOU,SIG_IGN);
  333.  
  334.     if((fp=open(totty,O_WRONLY)) < 0)
  335.     {    fputs("Can't open tty",stderr);
  336.         exit(1);
  337.     }
  338.  
  339.     time(&sec);
  340.     sprintf(message,format,ctime(&sec)+11,name,ttyname,name);
  341.  
  342.     InitScreen();
  343.     MsgPrint("[Waiting for your party to respond]",1);
  344.  
  345.     x=0;
  346.     do
  347.     {    if(x++ == 0)
  348.             write(fp,message,strlen(message));
  349.         if(x >= repeat)
  350.         {    MsgPrint("[Ringing your party again]",0);
  351.             x=0;
  352.         }
  353.     }while((st=WaitforConnect(channel)) == 0);
  354.         
  355.     close(fp);
  356.     return st;
  357. }
  358.  
  359. int CheckStatus(char *pipename)
  360. {
  361.     if(access(MakeChanName(pipename),0) < 0)
  362.         return MASTER;
  363.     else
  364.         return SLAVE;
  365. }
  366.  
  367. void main(int argc,char *argv[]) 
  368. {    char *totty,*pipename;
  369.     int channel;    /* communication pipe */
  370.     int lfl = 0, ring = 20;
  371.     
  372.     if(argc<2)    usage();
  373.  
  374.     while(--argc>0)            /* parse options */
  375.     {    if(*argv[1]=='-')
  376.         {    switch(*(++argv[1]))
  377.             {    case 'l':    lfl=1;
  378.                             break;
  379.                 default :    usage();
  380.             }
  381.             ++argv;
  382.         }
  383.     }    
  384.     InitTermcap();
  385.     ttraw(<old,<new); /* disable Ctrl-Z */
  386.  
  387.     switch(CheckStatus(argv[1]))
  388.     {    case MASTER :
  389.                 totty=BuildttyName(lfl,argv[1]);
  390.                 if((pipename = getenv("LOGNAME")) == NULL)
  391.                     pipename  = "root";
  392.  
  393.                 channel= MakeChan(pipename,MASTER);
  394.                 if(SendInvitation(totty,pipename,channel,ring) <0)
  395.                     break;
  396.                 StartTalk(channel);
  397.             break;
  398.         case SLAVE :
  399.                 pipename=argv[1];
  400.  
  401.                 channel= MakeChan(pipename,SLAVE);
  402.                 while(WaitforConnect(channel)==0);
  403.                 StartTalk(channel);
  404.             break;
  405.     }
  406.     clrscr();
  407.     MsgPrint("[Connection closing. Exiting]",1);
  408.     EndTermcap();
  409.  
  410.     ttcooked(<old);
  411.     exit(0);
  412. }